﻿#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <memory>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <iomanip>
#include <algorithm>
#include<queue>
#include <climits>
using namespace std;

struct Production {
    string left;
    vector<vector<string>> rights;
    int id;
    Production(string l, vector<vector<string>> r, int i) : left(l), rights(r), id(i) {}
};

struct Item {
    const Production* prod;
    int rhsIndex; // 新增字段，表示使用产生式右部的第几个候选式
    int dot;
    string lookahead;
    Item(const Production* p, int r, int d, string l)
        : prod(p), rhsIndex(r), dot(d), lookahead(l) {
    }
    bool operator<(const Item& other) const {
        if (prod->id != other.prod->id) return prod->id < other.prod->id;
        if (rhsIndex != other.rhsIndex) return rhsIndex < other.rhsIndex; // 新增比较
        if (dot != other.dot) return dot < other.dot;
        return lookahead < other.lookahead;
    }
    bool operator==(const Item& other) const {
        return prod->id == other.prod->id &&
            rhsIndex == other.rhsIndex &&
            dot == other.dot &&
            lookahead == other.lookahead;
    }
};

using Closure = set<Item>;

vector<Production> productions;
map<string, bool> nonTerminals;
map<string, set<string>> first;
vector<Closure> itemSets;
vector<map<string, string>> actionTable;
vector<map<string, int>> gotoTable;
vector<pair<int, string>> errors;

string trim(const string& s) {
    size_t start = s.find_first_not_of(" \t");
    size_t end = s.find_last_not_of(" \t");
    return (start == string::npos) ? "" : s.substr(start, end - start + 1);
}

vector<string> split(const string& s, char delim) {
    vector<string> tokens;
    string token;
    istringstream iss(s);
    while (getline(iss, token, delim)) {
        token = trim(token);
        if (token.empty()) continue;

        // 处理除 ε 外的符号：去除所有前后双引号
        if (token != "ε") {
            // 去除前导双引号
            size_t start = 0;
            while (start < token.size() && token[start] == '"') {
                start++;
            }
            // 去除尾部双引号
            size_t end = token.size();
            while (end > start && token[end - 1] == '"') {
                end--;
            }
            token = token.substr(start, end - start);
            token = trim(token); // 再次清理可能因去引号产生的空格
        }

        if (!token.empty()) {
            tokens.push_back(token);
        }
    }
    return tokens;
}

vector<vector<string>> parseProduction(const string& s) {
    vector<vector<string>> rights;
    vector<string> alts = split(s, '|');
    for (string& alt : alts) {
        alt = trim(alt);
        // 显式替换错误的"蔚"为正确的ε
        if (alt == "蔚") alt = "ε"; // 临时修复编码问题
        if (alt == "ε") {
            rights.push_back({});
            continue;
        }
        vector<string> symbols = split(alt, ' ');
        rights.push_back(symbols);
    }
    return rights;
}

void readGrammar(const string& filename) {
    ifstream file(filename);
    if (!file.is_open()) {
        throw runtime_error("Cannot open grammar file: " + filename);
    }

    string line;
    int id = 0;
    while (getline(file, line)) {
        line = trim(line);
        if (line.empty() || line[0] == '#') continue;

        size_t pos = line.find("->");//从→改到->时忘记字符数的差别了，要加一
        if (pos == string::npos) {
            cerr << "Warning: Invalid production format: " << line << endl;
            continue;
        }

        string left = trim(line.substr(0, pos));
        if (left.empty()) {
            cerr << "Warning: Empty left-hand side in production: " << line << endl;
            continue;
        }

        nonTerminals[left] = true;
        string rightStr = trim(line.substr(pos + 2));
        vector<vector<string>> rights = parseProduction(rightStr);

        if (rights.empty()) {
            cerr << "Warning: Empty right-hand side for production: " << left << endl;
            continue;
        }

        productions.emplace_back(left, rights, id++);

    }

    if (productions.empty()) {
        throw runtime_error("Abort: No valid productions found in grammar file");
    }

    // 安全插入拓广文法
    string startSymbol = productions.empty() ? "" : productions[0].left;
    productions.insert(
        productions.begin(),
        Production("S'", { {startSymbol} }, 0) // 临时 id
    );

    // 重新分配所有产生式的 id 为索引
    for (size_t i = 0; i < productions.size(); ++i) {
        productions[i].id = i;
    }

}

bool isTerminal(const string& s) {
    return !nonTerminals.count(s) && s != "ε";
}

void computeFirst() {
    // 初始化所有非终结符的FIRST集
    for (const auto& prod : productions) {
        first[prod.left];  // 确保每个非终结符都有条目
    }

    bool changed;
    do {
        changed = false;
        for (const Production& prod : productions) {
            string X = prod.left;
            for (const auto& rhs : prod.rights) {
                set<string> newFirst;
                bool canGenEpsilon = true;

                // 遍历产生式右部的每个符号
                for (const string& symbol : rhs) {
                    if (isTerminal(symbol)) {
                        // 终结符直接加入并停止
                        newFirst.insert(symbol);
                        canGenEpsilon = false;
                        break;
                    } else {
                        // 非终结符处理
                        const auto& symFirst = first[symbol];
                        bool hasEpsilon = false;

                        // 合并FIRST集
                        for (const string& f : symFirst) {
                            if (f == "ε") {
                                hasEpsilon = true;
                            } else {
                                newFirst.insert(f);
                            }
                        }

                        if (!hasEpsilon) {
                            canGenEpsilon = false;
                            break;
                        }
                    }
                }

                // 处理空产生式
                if (canGenEpsilon) {
                    newFirst.insert("ε");
                }

                // 更新当前非终结符的FIRST集
                size_t oldSize = first[X].size();
                for (const string& f : newFirst) {
                    first[X].insert(f);
                }
                if (first[X].size() > oldSize) {
                    changed = true;
                }
            }
        }
    } while (changed);
}
void printFirstSet() {
    // 将非终结符按字母顺序排序
    vector<string> ntOrder;
    for (const auto& entry : first) {
        ntOrder.push_back(entry.first);
    }
    sort(ntOrder.begin(), ntOrder.end());

    // 打印格式化输出
    cout << "FIRST Sets:\n";
    cout << string(40, '-') << endl;
    for (const string& nt : ntOrder) {
        cout << left << setw(15) << nt << ": { ";

        bool firstItem = true;
        // 将终结符按特定顺序排序：ε最后，其他按字母序
        vector<string> orderedTerminals;
        for (const string& t : first[nt]) {
            if (t != "ε") orderedTerminals.push_back(t);
        }
        sort(orderedTerminals.begin(), orderedTerminals.end());
        if (first[nt].count("ε")) orderedTerminals.push_back("ε");

        for (const string& t : orderedTerminals) {
            if (!firstItem) cout << ", ";
            // 特殊处理空串和运算符
            if (t == "ε") {
                cout << "ε";
            }
            else if (t.size() > 1 || isalnum(t[0])) {
                cout << t;
            }
            else {
                cout << "'" << t << "'";  // 给特殊符号加引号
            }
            firstItem = false;
        }
        cout << " }\n";
    }
    cout << string(40, '-') << endl;
}
Closure closure(const Closure& kernel) {
    Closure cl = kernel;
    queue<Item> q;
    for (const Item& item : cl) q.push(item);
    while (!q.empty()) {
        Item item = q.front(); q.pop();
        const auto& rhs = item.prod->rights[item.rhsIndex];
        if (item.dot >= rhs.size()) continue;
        string B = rhs[item.dot];
        if (!nonTerminals.count(B)) continue;

        // 正确构建beta：仅包含点后的符号
        vector<string> beta(rhs.begin() + item.dot + 1, rhs.end());
        set<string> firstBeta;
        bool canGenEpsilon = true;

        for (const string& s : beta) {
            if (isTerminal(s)) {
                firstBeta.insert(s);
                canGenEpsilon = false;
                break;
            }
            else {
                for (const string& f : first[s]) {
                    if (f != "ε") firstBeta.insert(f);
                }
                if (!first[s].count("ε")) {
                    canGenEpsilon = false;
                    break;
                }
            }
        }
        // 如果beta可以推导出ε，则加入原项的lookahead
        if (canGenEpsilon) {
            firstBeta.insert(item.lookahead);
        }

        for (const Production& prod : productions) {
            if (prod.left == B) {
                for (int r = 0; r < prod.rights.size(); ++r) {
                    for (const string& a : firstBeta) {
                        Item newItem(&prod, r, 0, a);
                        if (!cl.count(newItem)) {
                            cl.insert(newItem);
                            q.push(newItem);
                        }
                    }
                }
            }
        }
    }
    return cl;
}

Closure goTo(const Closure& cl, const string& X) {
    Closure kernel;
    for (const Item& item : cl) {
        const auto& rhs = item.prod->rights[item.rhsIndex]; // 使用正确的候选式
        if (item.dot < rhs.size() && rhs[item.dot] == X) {
            kernel.insert(Item(item.prod, item.rhsIndex, item.dot + 1, item.lookahead));
        }
    }
    return closure(kernel);
}

void buildLR1Items() {
    Closure initial;
    initial.insert(Item(&productions[0], 0, 0, "$"));
    itemSets.push_back(closure(initial));
    actionTable.resize(1);
    gotoTable.resize(1);
    queue<int> q;
    q.push(0);
    while (!q.empty()) {
        int state = q.front(); q.pop();
        const Closure& cl = itemSets[state];

        map<string, Closure> transitions;

        // 处理当前闭包中的所有项，收集归约和移进动作
        for (const Item& item : cl) {
            const Production* prod = item.prod;
            int rhsIndex = item.rhsIndex;
            const vector<string>& rhs = prod->rights[rhsIndex];

            if (item.dot == rhs.size()) { // 归约项
                if (prod->left == "S'") {
                    actionTable[state]["$"] = "acc";
                }
                else {
                    string action = "r" + to_string(prod->id);
                    if (actionTable[state].count(item.lookahead)) {
                        cerr << "Reduce-Conflict at state " << state << ": "
                            << actionTable[state][item.lookahead] << " vs " << action << endl;
                    }
                    string reduceAction = "r" + to_string(prod->id) + "-" + to_string(item.rhsIndex);
                    actionTable[state][item.lookahead] = reduceAction;
                }
            }
            else { // 移进项，收集转移符号
                string X = rhs[item.dot];
                transitions[X].insert(Item(prod, rhsIndex, item.dot + 1, item.lookahead));
            }
        }

        // 处理所有转移符号
        for (const auto& trans : transitions) {
            string X = trans.first;
            const Closure& kernel = trans.second;
            Closure newCl = closure(kernel);

            // 查找是否存在相同的闭包
            int newState = -1;
            for (size_t i = 0; i < itemSets.size(); ++i) {
                if (itemSets[i] == newCl) {
                    newState = i;
                    break;
                }
            }

            // 新状态处理
            if (newState == -1) {
                newState = itemSets.size();
                itemSets.push_back(newCl);
                actionTable.push_back(map<string, string>());
                gotoTable.push_back(map<string, int>());
                q.push(newState);
            }

            // 更新ACTION或GOTO表
            if (isTerminal(X)) {
                string shiftAction = "s" + to_string(newState);
                if (actionTable[state].count(X)) {
                    if (actionTable[state][X] != shiftAction) {
                        cerr << "Shift-Shift Conflict at state " << state
                            << " on symbol " << X << ": "
                            << actionTable[state][X] << " vs " << shiftAction << endl;
                    }
                }
                else {
                    actionTable[state][X] = shiftAction;
                }
            }
            else {
                gotoTable[state][X] = newState;
            }
        }
    }
}

vector<pair<string, int>> readTokens(const string& filename) {
    vector<pair<string, int>> tokens;
    ifstream file(filename);

    if (!file.is_open()) {
        cerr << "无法打开token文件: " << filename << endl;
        return tokens;
    }

    string line;
    while (getline(file, line)) {
        line = trim(line);
        if (line.empty()) continue;

        // 严格验证括号格式
        if (line.front() != '(' || line.back() != ')') {
            cerr << "非法token格式 (缺少括号): " << line << endl;
            continue;
        }

        // 安全提取括号内容
        string content;
        try {
            content = line.substr(1, line.size() - 2);  // 避免substr越界
        }
        catch (const out_of_range& e) {
            cerr << "括号内容提取失败: " << line << endl;
            continue;
        }

        vector<string> parts = split(content, ',');
        if (parts.size() != 3) {  // 强制要求严格的三元组格式
            cerr << "非法token格式 (需要3个字段): " << line << endl;
            continue;
        }

        // 验证行号
        int lineNo;
        try {
            lineNo = stoi(trim(parts[0]));
        }
        catch (const invalid_argument& e) {
            cerr << "非法行号: " << parts[0] << " in line: " << line << endl;
            continue;
        }
        catch (const out_of_range& e) {
            cerr << "行号超出范围: " << parts[0] << endl;
            continue;
        }

        // 提取类型和内容
        string type = trim(parts[1]);
        string tokenContent = trim(parts[2]);

        // 内容非空校验
        if (tokenContent.empty()) {
            cerr << "Token内容为空: " << line << endl;
            continue;
        }

        // 处理带引号的token内容（如包含逗号）
        if (tokenContent.front() == '"' && tokenContent.back() == '"') {
            tokenContent = tokenContent.substr(1, tokenContent.size() - 2);
        }

        // 生成最终token
        if (type == "Keyword" || type == "Operator" || type == "Delimiter") {
            tokens.emplace_back(tokenContent, lineNo);
        }
        else {
            tokens.emplace_back(type, lineNo);  // 处理Identifier/constant等类型          ////注意，这里为了测试把第一个参数改成tokenContent了，本来是type的
        }
    }

    tokens.emplace_back("$", -1);  // 添加结束标记
    return tokens;
}

/*bool parseTokens(const vector<pair<string, int>>& tokens) {
    stack<int> states;
    stack<string> symbols;
    states.push(0);
    int ptr = 0;
    while (true) {
        int s = states.top();
        if (ptr >= tokens.size()) { // 越界检查
            errors.emplace_back(-1, "Unexpected end of input");
            return false;
        }
        string a = tokens[ptr].first;
        string action = actionTable[s][a];
        if (action[0] == 's') {
            int newState = stoi(action.substr(1));
            states.push(newState);
            symbols.push(a);
            ptr++;
        }
        else if (action[0] == 'r') {
            // 解析产生式ID和候选式索引
            size_t dashPos = action.find('-');
            if (dashPos == string::npos) {
                errors.emplace_back(tokens[ptr].second, "Invalid reduce action format: " + action);
                return false;
            }

            // 分割字符串获取ID和索引
            int prodId = stoi(action.substr(1, dashPos - 1));
            int rhsIndex = stoi(action.substr(dashPos + 1));

            // 获取对应产生式
            Production& prod = productions[prodId];
            if (rhsIndex < 0 || rhsIndex >= prod.rights.size()) {
                errors.emplace_back(tokens[ptr].second, "Invalid production index in reduce action");
                return false;
            }

            // 确定弹出数量（候选式右部长度）
            int popLen = prod.rights[rhsIndex].size();
            if (states.size() < popLen || symbols.size() < popLen) {
                errors.emplace_back(tokens[ptr].second, "Stack underflow during reduction");
                return false;
            }

            // 弹出状态和符号
            for (int i = 0; i < popLen; ++i) {
                states.pop();
                symbols.pop();
            }

            // 处理GOTO
            symbols.push(prod.left);
            int currState = states.top();
            if (gotoTable[currState].count(prod.left) == 0) {
                errors.emplace_back(tokens[ptr].second, "Goto failed for " + prod.left);
                return false;
            }
            states.push(gotoTable[currState][prod.left]);
        }
        else if (action == "acc") {
            return true;
        }
        else {
            errors.emplace_back(tokens[ptr].second, "Invalid action '" + action + "'");
            return false;
        }
    }
}*/
// 打印ACTION表
void printActionTable() {
    // 收集所有终结符(包括$)
    set<string> terminals;
    for (const auto& state : actionTable) {
        for (const auto& entry : state) {
            terminals.insert(entry.first);
        }
    }

    // 保证$在最后
    if (terminals.count("$")) {
        terminals.erase("$");
        terminals.insert("$");
    }

    // 打印表头
    cout << "\nACTION Table:\n";
    cout << left << setw(8) << "State";
    for (const auto& t : terminals) {
        cout << setw(8) << t;
    }
    cout << "\n" << string(8 + 8 * terminals.size(), '-') << endl;

    // 打印每个状态的行
    for (size_t state = 0; state < actionTable.size(); ++state) {
        cout << setw(8) << state;
        for (const auto& t : terminals) {
            auto it = actionTable[state].find(t);
            if (it != actionTable[state].end()) {
                cout << setw(8) << it->second;
            }
            else {
                cout << setw(8) << "";
            }
        }
        cout << endl;
    }
}

// 打印GOTO表
void printGotoTable() {
    // 收集所有非终结符(排除S')
    set<string> nonTerms;
    for (const auto& state : gotoTable) {
        for (const auto& entry : state) {
            if (entry.first != "S'") {
                nonTerms.insert(entry.first);
            }
        }
    }

    // 打印表头
    cout << "\nGOTO Table:\n";
    cout << left << setw(8) << "State";
    for (const auto& nt : nonTerms) {
        cout << setw(8) << nt;
    }
    cout << "\n" << string(8 + 8 * nonTerms.size(), '-') << endl;

    // 打印每个状态的行
    for (size_t state = 0; state < gotoTable.size(); ++state) {
        cout << setw(8) << state;
        for (const auto& nt : nonTerms) {
            auto it = gotoTable[state].find(nt);
            if (it != gotoTable[state].end()) {
                cout << setw(8) << it->second;
            }
            else {
                cout << setw(8) << "";
            }
        }
        cout << endl;
    }
}
void printItemSets() {
    cout << "\nLR(1) Item Sets:\n";
    cout << string(60, '=') << endl;

    for (size_t state = 0; state < itemSets.size(); ++state) {
        const Closure& cl = itemSets[state];

        // 打印状态头
        cout << "State " << state << " (" << cl.size() << " items):\n";
        cout << string(40, '-') << endl;

        // 按产生式ID和候选式索引排序，使输出更有序
        map<int, map<int, vector<Item>>> sortedItems;
        for (const Item& item : cl) {
            sortedItems[item.prod->id][item.rhsIndex].push_back(item);
        }

        // 打印每个项目
        for (auto& [prodId, rhsMap] : sortedItems) {
            const Production& prod = productions[prodId];

            for (auto& [rhsIdx, items] : rhsMap) {
                const vector<string>& rhs = prod.rights[rhsIdx];

                // 生成候选式字符串表示
                string rhsStr;
                for (const string& sym : rhs) {
                    rhsStr += (sym.empty() ? "ε" : sym) + " ";
                }
                if (rhsStr.empty()) rhsStr = "ε ";
                else rhsStr.pop_back(); // 移除末尾空格

                // 收集所有不同的点位置和对应的展望符
                map<int, set<string>> dotMap;
                for (const Item& item : items) {
                    dotMap[item.dot].insert(item.lookahead);
                }

                // 为每个点位置生成项目表示
                for (auto& [dotPos, lookaheads] : dotMap) {
                    // 生成带点的产生式右部
                    string dottedRhs;
                    int i = 0;
                    for (; i < dotPos && i < rhs.size(); ++i) {
                        dottedRhs += rhs[i] + " ";
                    }
                    dottedRhs += ". "; // 添加点
                    for (; i < rhs.size(); ++i) {
                        dottedRhs += rhs[i] + " ";
                    }
                    if (dottedRhs.back() == ' ') dottedRhs.pop_back();

                    // 处理空产生式特殊情况
                    if (rhs.empty()) dottedRhs = ". ε";

                    // 生成展望符
                    string lookaheadStr;
                    for (auto it = lookaheads.begin(); it != lookaheads.end(); ++it) {
                        if (it != lookaheads.begin()) lookaheadStr += "/";
                        lookaheadStr += *it;
                    }

                    // 格式化输出
                    cout << left << setw(25)
                        << (prod.left + " -> " + dottedRhs)
                        << " , " << lookaheadStr << "\n";
                }
            }
        }
        cout << string(40, '-') << endl << endl;
    }
}
struct ParseStep {
    vector<int> stateStack;
    vector<string> symbolStack;
    vector<pair<string, int>> remainingInput;
    string action;
};

vector<ParseStep> parseSteps;

void printParseStep(const ParseStep& step) {
    // 打印状态栈
    cout << "States: [";
    for (size_t i = 0; i < step.stateStack.size(); ++i) {
        cout << step.stateStack[i];
        if (i != step.stateStack.size() - 1) cout << " ";
    }
    cout << "]  ";

    // 打印符号栈
    cout << "Symbols: [";
    for (size_t i = 0; i < step.symbolStack.size(); ++i) {
        string sym = step.symbolStack[i];
        if (sym.empty()) sym = "ε";
        cout << sym;
        if (i != step.symbolStack.size() - 1) cout << " ";
    }
    cout << "]  ";

    // 打印剩余输入
    cout << "Input: [";
    for (size_t i = 0; i < step.remainingInput.size(); ++i) {
        cout << step.remainingInput[i].first;
        if (i != step.remainingInput.size() - 1) cout << " ";
    }
    cout << "]  ";

    // 打印动作
    cout << "Action: " << step.action << endl;
}

void recordStep(int state, const stack<int>& states,
    const stack<string>& symbols,
    const vector<pair<string, int>>& tokens,
    int ptr, const string& action) {
    ParseStep step;

    // 复制状态栈
    stack<int> stateCopy = states;
    while (!stateCopy.empty()) {
        step.stateStack.insert(step.stateStack.begin(), stateCopy.top());
        stateCopy.pop();
    }

    // 复制符号栈
    stack<string> symbolCopy = symbols;
    while (!symbolCopy.empty()) {
        step.symbolStack.insert(step.symbolStack.begin(), symbolCopy.top());
        symbolCopy.pop();
    }

    // 复制剩余输入
    for (int i = ptr; i < tokens.size(); ++i) {
        step.remainingInput.push_back(tokens[i]);
    }

    step.action = action;
    parseSteps.push_back(step);
}

bool parseTokensWithTrace(const vector<pair<string, int>>& tokens) {
    stack<int> states;
    stack<string> symbols;
    states.push(0);
    int ptr = 0;

    // 记录初始状态
    recordStep(0, states, symbols, tokens, ptr, "Initialize");

    while (true) {
        int s = states.top();
        string a = (ptr < tokens.size()) ? tokens[ptr].first : "$";

        // 记录当前状态
        stringstream actionMsg;

        if (actionTable[s].count(a) == 0) {
            errors.emplace_back(
                (ptr < tokens.size()) ? tokens[ptr].second : -1,
                "Unexpected symbol '" + a + "'"
            );
            recordStep(s, states, symbols, tokens, ptr, "ERROR: Unexpected symbol " + a);
            return false;
        }

        string action = actionTable[s][a];

        if (action[0] == 's') { // Shift
            int newState = stoi(action.substr(1));
            states.push(newState);
            symbols.push(a);
            actionMsg << "Shift to state " << newState;
            ptr++;

            recordStep(s, states, symbols, tokens, ptr, actionMsg.str());

        }
        else if (action[0] == 'r') { // Reduce
            size_t dashPos = action.find('-');
            int prodId = stoi(action.substr(1, dashPos - 1));
            int rhsIndex = stoi(action.substr(dashPos + 1));

            const Production& prod = productions[prodId];
            int popLen = prod.rights[rhsIndex].size();

            // 记录规约动作
            actionMsg << "Reduce using " << prod.left << " -> ";
            for (const auto& sym : prod.rights[rhsIndex]) {
                actionMsg << sym << " ";
            }
            if (prod.rights[rhsIndex].empty()) actionMsg << "ε";

            // 执行规约
            for (int i = 0; i < popLen; ++i) {
                if (states.empty() || symbols.empty()) {
                    errors.emplace_back(tokens[ptr].second, "Stack underflow");
                    return false;
                }
                states.pop();
                symbols.pop();
            }

            symbols.push(prod.left);
            int newState = states.top();
            states.push(gotoTable[newState][prod.left]);

            recordStep(s, states, symbols, tokens, ptr, actionMsg.str());

        }
        else if (action == "acc") { // Accept
            recordStep(s, states, symbols, tokens, ptr, "ACCEPT");
            return true;
        }
    }
}
int main() {

    readGrammar("grammar.txt");
    computeFirst();
    printFirstSet();
    actionTable.resize(itemSets.size());
    gotoTable.resize(itemSets.size());
   buildLR1Items();
   printItemSets();
   printActionTable();
   printGotoTable();
   
    auto tokens = readTokens("tokens.txt");
    parseSteps.clear();

    bool success = parseTokensWithTrace(tokens);

    // 打印分析过程
    cout << "\nParsing Process Trace:\n";
    cout << string(120, '=') << endl;
    for (const auto& step : parseSteps) {
        printParseStep(step);
    }
    cout << string(120, '=') << endl;
    cout << string(120, '=') << endl;
    if (success) {
        cout << "YES" << endl;
    }
    else {
        cout << "NO" << endl;
        ofstream errorFile("errors.txt");
        for (auto& e : errors) {
            errorFile << "Line " << e.first << ": " << e.second << endl;
        }
    }
    return 0;
}